Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-009.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 1065343 objects.
Mean distance to the closest unit in the map: 1.308.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_dia_2k.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt          tmax       
 Length:1065343     Length:1065343     Min.   :  1.0   Min.   :-196.0  
 Class :character   Class :character   1st Qu.: 91.0   1st Qu.: 144.0  
 Mode  :character   Mode  :character   Median :183.0   Median : 201.0  
                                       Mean   :182.8   Mean   : 201.5  
                                       3rd Qu.:274.0   3rd Qu.: 263.0  
                                       Max.   :366.0   Max.   : 469.0  
      tmin             precip            nevada    prof_nieve       
 Min.   :-252.00   Min.   :   0.00   Min.   :0   Min.   :   0.0000  
 1st Qu.:  47.00   1st Qu.:   0.00   1st Qu.:0   1st Qu.:   0.0000  
 Median : 100.00   Median :   0.00   Median :0   Median :   0.0000  
 Mean   :  97.54   Mean   :  17.05   Mean   :0   Mean   :   0.6185  
 3rd Qu.: 153.00   3rd Qu.:   2.00   3rd Qu.:0   3rd Qu.:   0.0000  
 Max.   : 332.00   Max.   :3361.00   Max.   :0   Max.   :1240.0000  
    longitud        latitud           altitud    
 Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:39.47   1st Qu.: -4.850   1st Qu.:  47  
 Median :41.29   Median : -1.411   Median : 287  
 Mean   :40.10   Mean   : -2.391   Mean   : 486  
 3rd Qu.:42.22   3rd Qu.:  1.296   3rd Qu.: 691  
 Max.   :43.57   Max.   :  4.216   Max.   :2535  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

    1     2     3     4     5     6     7     8     9    10    11    12    13 
54463 52899 26980 52926 46382 94404 61855 33769 38932  8243 45500 46953 61333 
   14    15    16    17    18    19    20    21    22    23    24    25 
28520  1419 64536 29630 57208 67856  5980 27869 39197 45310 50794 22385 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("fecha_cnt", "tmax", "tmin", "precip", "longitud", "latitud", "altitud")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
      fecha_cnt       tmax       tmin     precip   longitud    latitud
[1,] -0.0125219 -0.7943774 -0.8277120 0.28545532  0.4473245  0.3629498
[2,] -0.8893345 -0.3437403 -0.2960724 0.01516313 -0.1775230 -0.2983449
         altitud
[1,] 0.269786486
[2,] 0.009048257

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
 longitud    precip   latitud fecha_cnt      tmax      tmin   altitud 
0.9482129 0.9134272 0.9117051 0.8996949 0.8888956 0.8751809 0.8636442 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip           nevada 
 Min.   :  1.0   Min.   :-80.0   Min.   :-240.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 92.0   1st Qu.:153.0   1st Qu.:  54.0   1st Qu.:  0.00   1st Qu.:0  
 Median :183.0   Median :208.0   Median : 105.0   Median :  0.00   Median :0  
 Mean   :182.9   Mean   :209.5   Mean   : 103.2   Mean   : 14.96   Mean   :0  
 3rd Qu.:274.0   3rd Qu.:267.0   3rd Qu.: 156.0   3rd Qu.:  1.00   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   : 332.0   Max.   :639.00   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:38.99   1st Qu.: -5.498   1st Qu.:  43.0  
 Median :   0.0000   Median :41.15   Median : -1.861   Median : 251.0  
 Mean   :   0.1214   Mean   :39.97   Mean   : -2.592   Mean   : 380.5  
 3rd Qu.:   0.0000   3rd Qu.:42.08   3rd Qu.:  1.179   3rd Qu.: 632.0  
 Max.   :1240.0000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax              tmin              precip      
 Min.   :  1.0   Min.   :-196.00   Min.   :-252.000   Min.   :  0.00  
 1st Qu.: 86.0   1st Qu.:  23.00   1st Qu.: -37.000   1st Qu.:  0.00  
 Median :178.0   Median :  75.00   Median :   8.000   Median :  0.00  
 Mean   :180.8   Mean   :  75.11   Mean   :   6.723   Mean   : 31.43  
 3rd Qu.:277.0   3rd Qu.: 130.00   3rd Qu.:  56.000   3rd Qu.: 25.00  
 Max.   :366.0   Max.   : 255.00   Max.   : 176.000   Max.   :529.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.18   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.2717  
 Mean   :0   Mean   :   8.586   Mean   :42.27   Mean   :  0.8202  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1199.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   : 507  
 1st Qu.:1971  
 Median :2247  
 Mean   :2185  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :  3.0   Min.   :-63   Min.   :-133.00   Min.   : 620.0   Min.   :0  
 1st Qu.:106.0   1st Qu.:103   1st Qu.:  53.00   1st Qu.: 689.5   1st Qu.:0  
 Median :271.0   Median :147   Median : 101.00   Median : 782.0   Median :0  
 Mean   :217.3   Mean   :144   Mean   :  90.77   Mean   : 866.2   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194   3rd Qu.: 136.50   3rd Qu.: 939.0   3rd Qu.:0  
 Max.   :362.0   Max.   :332   Max.   : 240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -1.8237   1st Qu.:  44.0  
 Median :  0.000   Median :41.57   Median :  0.9517   Median : 251.0  
 Mean   :  2.675   Mean   :40.75   Mean   : -0.7228   Mean   : 604.5  
 3rd Qu.:  0.000   3rd Qu.:42.27   3rd Qu.:  2.1053   3rd Qu.: 916.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip            nevada 
 Min.   :  1.0   Min.   :-80.0   Min.   :-240.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 91.0   1st Qu.:154.0   1st Qu.:  53.0   1st Qu.:  0.000   1st Qu.:0  
 Median :183.0   Median :210.0   Median : 105.0   Median :  0.000   Median :0  
 Mean   :182.5   Mean   :211.1   Mean   : 103.4   Mean   :  6.805   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:269.0   3rd Qu.: 158.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   : 332.0   Max.   :322.000   Max.   :0  
   prof_nieve           longitud        latitud           altitud      
 Min.   :   0.0000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:38.95   1st Qu.: -5.498   1st Qu.:  43.0  
 Median :   0.0000   Median :41.15   Median : -1.861   Median : 251.0  
 Mean   :   0.1149   Mean   :39.92   Mean   : -2.610   Mean   : 380.9  
 3rd Qu.:   0.0000   3rd Qu.:42.07   3rd Qu.:  1.179   3rd Qu.: 639.0  
 Max.   :1240.0000   Max.   :43.57   Max.   :  4.216   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax              tmin              precip      
 Min.   :  1.0   Min.   :-196.00   Min.   :-252.000   Min.   :  0.00  
 1st Qu.: 86.0   1st Qu.:  23.00   1st Qu.: -37.000   1st Qu.:  0.00  
 Median :178.0   Median :  75.00   Median :   8.000   Median :  0.00  
 Mean   :180.8   Mean   :  75.11   Mean   :   6.723   Mean   : 31.43  
 3rd Qu.:277.0   3rd Qu.: 130.00   3rd Qu.:  56.000   3rd Qu.: 25.00  
 Max.   :366.0   Max.   : 255.00   Max.   : 176.000   Max.   :529.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.18   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.2717  
 Mean   :0   Mean   :   8.586   Mean   :42.27   Mean   :  0.8202  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1199.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   : 507  
 1st Qu.:1971  
 Median :2247  
 Mean   :2185  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip        nevada 
 Min.   :  1.0   Min.   :-64.0   Min.   :-117.00   Min.   : 84   Min.   :0  
 1st Qu.: 98.0   1st Qu.:126.0   1st Qu.:  67.00   1st Qu.:149   1st Qu.:0  
 Median :178.0   Median :160.0   Median :  98.00   Median :193   Median :0  
 Mean   :191.4   Mean   :166.5   Mean   :  97.17   Mean   :229   Mean   :0  
 3rd Qu.:295.0   3rd Qu.:202.0   3rd Qu.: 129.00   3rd Qu.:275   3rd Qu.:0  
 Max.   :366.0   Max.   :379.0   Max.   : 254.00   Max.   :639   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.80   1st Qu.: -5.598   1st Qu.:  58.0  
 Median :  0.000   Median :41.84   Median : -1.861   Median : 258.0  
 Mean   :  0.294   Mean   :41.34   Mean   : -2.117   Mean   : 369.1  
 3rd Qu.:  0.000   3rd Qu.:42.70   3rd Qu.:  1.401   3rd Qu.: 594.0  
 Max.   :780.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :  3.0   Min.   :-63   Min.   :-133.00   Min.   : 620.0   Min.   :0  
 1st Qu.:106.0   1st Qu.:103   1st Qu.:  53.00   1st Qu.: 689.5   1st Qu.:0  
 Median :271.0   Median :147   Median : 101.00   Median : 782.0   Median :0  
 Mean   :217.3   Mean   :144   Mean   :  90.77   Mean   : 866.2   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194   3rd Qu.: 136.50   3rd Qu.: 939.0   3rd Qu.:0  
 Max.   :362.0   Max.   :332   Max.   : 240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -1.8237   1st Qu.:  44.0  
 Median :  0.000   Median :41.57   Median :  0.9517   Median : 251.0  
 Mean   :  2.675   Mean   :40.75   Mean   : -0.7228   Mean   : 604.5  
 3rd Qu.:  0.000   3rd Qu.:42.27   3rd Qu.:  2.1053   3rd Qu.: 916.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin             precip       
 Min.   :  1.0   Min.   :-80.0   Min.   :-240.00   Min.   :  0.000  
 1st Qu.: 92.0   1st Qu.:152.0   1st Qu.:  50.00   1st Qu.:  0.000  
 Median :183.0   Median :206.0   Median : 100.00   Median :  0.000  
 Mean   :182.6   Mean   :209.8   Mean   :  99.03   Mean   :  6.982  
 3rd Qu.:272.0   3rd Qu.:270.0   3rd Qu.: 151.00   3rd Qu.:  0.000  
 Max.   :366.0   Max.   :469.0   Max.   : 332.00   Max.   :187.000  
     nevada    prof_nieve           longitud        latitud      
 Min.   :0   Min.   :   0.0000   Min.   :35.28   Min.   :-8.624  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.85   1st Qu.:-4.127  
 Median :0   Median :   0.0000   Median :41.29   Median :-1.293  
 Mean   :0   Mean   :   0.1231   Mean   :40.74   Mean   :-1.646  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.11   3rd Qu.: 1.331  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  52.0  
 Median : 261.0  
 Mean   : 380.8  
 3rd Qu.: 656.0  
 Max.   :2230.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax              tmin              precip      
 Min.   :  1.0   Min.   :-196.00   Min.   :-252.000   Min.   :  0.00  
 1st Qu.: 86.0   1st Qu.:  23.00   1st Qu.: -37.000   1st Qu.:  0.00  
 Median :178.0   Median :  75.00   Median :   8.000   Median :  0.00  
 Mean   :180.8   Mean   :  75.11   Mean   :   6.723   Mean   : 31.43  
 3rd Qu.:277.0   3rd Qu.: 130.00   3rd Qu.:  56.000   3rd Qu.: 25.00  
 Max.   :366.0   Max.   : 255.00   Max.   : 176.000   Max.   :529.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.18   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.2717  
 Mean   :0   Mean   :   8.586   Mean   :42.27   Mean   :  0.8202  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1199.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   : 507  
 1st Qu.:1971  
 Median :2247  
 Mean   :2185  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip        nevada 
 Min.   :  1.0   Min.   :-64.0   Min.   :-117.00   Min.   : 84   Min.   :0  
 1st Qu.: 98.0   1st Qu.:126.0   1st Qu.:  67.00   1st Qu.:149   1st Qu.:0  
 Median :178.0   Median :160.0   Median :  98.00   Median :193   Median :0  
 Mean   :191.4   Mean   :166.5   Mean   :  97.17   Mean   :229   Mean   :0  
 3rd Qu.:295.0   3rd Qu.:202.0   3rd Qu.: 129.00   3rd Qu.:275   3rd Qu.:0  
 Max.   :366.0   Max.   :379.0   Max.   : 254.00   Max.   :639   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.80   1st Qu.: -5.598   1st Qu.:  58.0  
 Median :  0.000   Median :41.84   Median : -1.861   Median : 258.0  
 Mean   :  0.294   Mean   :41.34   Mean   : -2.117   Mean   : 369.1  
 3rd Qu.:  0.000   3rd Qu.:42.70   3rd Qu.:  1.401   3rd Qu.: 594.0  
 Max.   :780.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :  3.0   Min.   :-63   Min.   :-133.00   Min.   : 620.0   Min.   :0  
 1st Qu.:106.0   1st Qu.:103   1st Qu.:  53.00   1st Qu.: 689.5   1st Qu.:0  
 Median :271.0   Median :147   Median : 101.00   Median : 782.0   Median :0  
 Mean   :217.3   Mean   :144   Mean   :  90.77   Mean   : 866.2   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194   3rd Qu.: 136.50   3rd Qu.: 939.0   3rd Qu.:0  
 Max.   :362.0   Max.   :332   Max.   : 240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -1.8237   1st Qu.:  44.0  
 Median :  0.000   Median :41.57   Median :  0.9517   Median : 251.0  
 Mean   :  2.675   Mean   :40.75   Mean   : -0.7228   Mean   : 604.5  
 3rd Qu.:  0.000   3rd Qu.:42.27   3rd Qu.:  2.1053   3rd Qu.: 916.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :-18.0   Min.   :-75.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 90.0   1st Qu.:208.0   1st Qu.:146.0   1st Qu.:  0.000   1st Qu.:0  
 Median :179.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :180.9   Mean   :229.3   Mean   :164.7   Mean   :  4.341   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :429.0   Max.   :322.0   Max.   :322.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud    
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25  
 Median :0    Median :28.44   Median :-16.33   Median :  33  
 Mean   :0    Mean   :28.38   Mean   :-16.06   Mean   : 382  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin            precip            nevada 
 Min.   : 61.0   Min.   :-80.0   Min.   :-240.0   Min.   :  0.000   Min.   :0  
 1st Qu.:207.0   1st Qu.:180.0   1st Qu.:  80.0   1st Qu.:  0.000   1st Qu.:0  
 Median :258.0   Median :249.0   Median : 134.0   Median :  0.000   Median :0  
 Mean   :258.5   Mean   :238.1   Mean   : 124.6   Mean   :  5.756   Mean   :0  
 3rd Qu.:312.0   3rd Qu.:299.0   3rd Qu.: 176.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :469.0   Max.   : 332.0   Max.   :180.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud      
 Min.   :   0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:39.85   1st Qu.:-4.127   1st Qu.:  52.0  
 Median :   0.0000   Median :41.29   Median :-1.411   Median : 261.0  
 Mean   :   0.1123   Mean   :40.76   Mean   :-1.698   Mean   : 387.1  
 3rd Qu.:   0.0000   3rd Qu.:42.12   3rd Qu.: 1.296   3rd Qu.: 667.0  
 Max.   :1240.0000   Max.   :43.57   Max.   : 4.216   Max.   :2230.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax              tmin              precip      
 Min.   :  1.0   Min.   :-196.00   Min.   :-252.000   Min.   :  0.00  
 1st Qu.: 86.0   1st Qu.:  23.00   1st Qu.: -37.000   1st Qu.:  0.00  
 Median :178.0   Median :  75.00   Median :   8.000   Median :  0.00  
 Mean   :180.8   Mean   :  75.11   Mean   :   6.723   Mean   : 31.43  
 3rd Qu.:277.0   3rd Qu.: 130.00   3rd Qu.:  56.000   3rd Qu.: 25.00  
 Max.   :366.0   Max.   : 255.00   Max.   : 176.000   Max.   :529.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.18   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.2717  
 Mean   :0   Mean   :   8.586   Mean   :42.27   Mean   :  0.8202  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1199.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   : 507  
 1st Qu.:1971  
 Median :2247  
 Mean   :2185  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin             precip        nevada 
 Min.   :  1.0   Min.   :-64.0   Min.   :-117.00   Min.   : 84   Min.   :0  
 1st Qu.: 98.0   1st Qu.:126.0   1st Qu.:  67.00   1st Qu.:149   1st Qu.:0  
 Median :178.0   Median :160.0   Median :  98.00   Median :193   Median :0  
 Mean   :191.4   Mean   :166.5   Mean   :  97.17   Mean   :229   Mean   :0  
 3rd Qu.:295.0   3rd Qu.:202.0   3rd Qu.: 129.00   3rd Qu.:275   3rd Qu.:0  
 Max.   :366.0   Max.   :379.0   Max.   : 254.00   Max.   :639   Max.   :0  
   prof_nieve         longitud        latitud           altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.80   1st Qu.: -5.598   1st Qu.:  58.0  
 Median :  0.000   Median :41.84   Median : -1.861   Median : 258.0  
 Mean   :  0.294   Mean   :41.34   Mean   : -2.117   Mean   : 369.1  
 3rd Qu.:  0.000   3rd Qu.:42.70   3rd Qu.:  1.401   3rd Qu.: 594.0  
 Max.   :780.000   Max.   :43.57   Max.   :  4.216   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin             precip       
 Min.   :  1.00   Min.   :-44.0   Min.   :-185.00   Min.   :  0.000  
 1st Qu.: 39.00   1st Qu.:133.0   1st Qu.:  28.00   1st Qu.:  0.000  
 Median : 77.00   Median :170.0   Median :  66.00   Median :  0.000  
 Mean   : 78.38   Mean   :170.8   Mean   :  63.87   Mean   :  8.666  
 3rd Qu.:116.00   3rd Qu.:211.0   3rd Qu.: 101.00   3rd Qu.:  2.000  
 Max.   :230.00   Max.   :360.0   Max.   : 210.00   Max.   :187.000  
     nevada    prof_nieve           longitud        latitud      
 Min.   :0   Min.   :   0.0000   Min.   :35.28   Min.   :-8.624  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.56   1st Qu.:-4.127  
 Median :0   Median :   0.0000   Median :41.29   Median :-1.229  
 Mean   :0   Mean   :   0.1379   Mean   :40.72   Mean   :-1.576  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.08   3rd Qu.: 1.363  
 Max.   :0   Max.   :1209.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  52.0  
 Median : 261.0  
 Mean   : 372.1  
 3rd Qu.: 639.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :  3.0   Min.   :-63   Min.   :-133.00   Min.   : 620.0   Min.   :0  
 1st Qu.:106.0   1st Qu.:103   1st Qu.:  53.00   1st Qu.: 689.5   1st Qu.:0  
 Median :271.0   Median :147   Median : 101.00   Median : 782.0   Median :0  
 Mean   :217.3   Mean   :144   Mean   :  90.77   Mean   : 866.2   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194   3rd Qu.: 136.50   3rd Qu.: 939.0   3rd Qu.:0  
 Max.   :362.0   Max.   :332   Max.   : 240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -1.8237   1st Qu.:  44.0  
 Median :  0.000   Median :41.57   Median :  0.9517   Median : 251.0  
 Mean   :  2.675   Mean   :40.75   Mean   : -0.7228   Mean   : 604.5  
 3rd Qu.:  0.000   3rd Qu.:42.27   3rd Qu.:  2.1053   3rd Qu.: 916.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :-18.0   Min.   :-75.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 90.0   1st Qu.:208.0   1st Qu.:146.0   1st Qu.:  0.000   1st Qu.:0  
 Median :179.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :180.9   Mean   :229.3   Mean   :164.7   Mean   :  4.341   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :429.0   Max.   :322.0   Max.   :322.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud    
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25  
 Median :0    Median :28.44   Median :-16.33   Median :  33  
 Mean   :0    Mean   :28.38   Mean   :-16.06   Mean   : 382  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 61.0   Min.   :119.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:190.0   1st Qu.:245.0   1st Qu.:130.0   1st Qu.:  0.000   1st Qu.:0  
 Median :225.0   Median :282.0   Median :160.0   Median :  0.000   Median :0  
 Mean   :225.8   Mean   :280.5   Mean   :158.7   Mean   :  4.245   Mean   :0  
 3rd Qu.:261.0   3rd Qu.:315.0   3rd Qu.:190.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :365.0   Max.   :469.0   Max.   :332.0   Max.   :180.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud      
 Min.   :   0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:39.56   1st Qu.:-4.049   1st Qu.:  44.0  
 Median :   0.0000   Median :41.22   Median :-1.169   Median : 247.0  
 Mean   :   0.0048   Mean   :40.76   Mean   :-1.573   Mean   : 371.6  
 3rd Qu.:   0.0000   3rd Qu.:42.11   3rd Qu.: 1.363   3rd Qu.: 639.0  
 Max.   :1039.0000   Max.   :43.57   Max.   : 4.216   Max.   :2230.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip       
 Min.   :189.0   Min.   :-80.0   Min.   :-240.00   Min.   :  0.000  
 1st Qu.:312.0   1st Qu.:116.0   1st Qu.:  18.00   1st Qu.:  0.000  
 Median :332.0   Median :150.0   Median :  53.00   Median :  0.000  
 Mean   :328.8   Mean   :146.7   Mean   :  51.02   Mean   :  9.014  
 3rd Qu.:349.0   3rd Qu.:179.0   3rd Qu.:  85.00   3rd Qu.:  2.000  
 Max.   :366.0   Max.   :320.0   Max.   : 204.00   Max.   :158.000  
     nevada    prof_nieve           longitud        latitud      
 Min.   :0   Min.   :   0.0000   Min.   :35.28   Min.   :-8.624  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.88   1st Qu.:-4.846  
 Median :0   Median :   0.0000   Median :41.38   Median :-1.885  
 Mean   :0   Mean   :   0.3441   Mean   :40.76   Mean   :-1.967  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.18   3rd Qu.: 1.168  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  72.0  
 Median : 370.0  
 Mean   : 420.6  
 3rd Qu.: 687.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax              tmin              precip      
 Min.   :  1.0   Min.   :-196.00   Min.   :-252.000   Min.   :  0.00  
 1st Qu.: 86.0   1st Qu.:  23.00   1st Qu.: -37.000   1st Qu.:  0.00  
 Median :178.0   Median :  75.00   Median :   8.000   Median :  0.00  
 Mean   :180.8   Mean   :  75.11   Mean   :   6.723   Mean   : 31.43  
 3rd Qu.:277.0   3rd Qu.: 130.00   3rd Qu.:  56.000   3rd Qu.: 25.00  
 Max.   :366.0   Max.   : 255.00   Max.   : 176.000   Max.   :529.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.18   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.2717  
 Mean   :0   Mean   :   8.586   Mean   :42.27   Mean   :  0.8202  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1199.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   : 507  
 1st Qu.:1971  
 Median :2247  
 Mean   :2185  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax          tmin             precip        nevada 
 Min.   :  1.0   Min.   :-64   Min.   :-117.00   Min.   :279   Min.   :0  
 1st Qu.:101.0   1st Qu.:120   1st Qu.:  66.00   1st Qu.:326   1st Qu.:0  
 Median :236.0   Median :157   Median : 102.00   Median :378   Median :0  
 Mean   :205.6   Mean   :163   Mean   :  98.67   Mean   :400   Mean   :0  
 3rd Qu.:304.0   3rd Qu.:204   3rd Qu.: 134.00   3rd Qu.:457   3rd Qu.:0  
 Max.   :366.0   Max.   :369   Max.   : 254.00   Max.   :639   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.78   1st Qu.: -5.3456   1st Qu.:  44.0  
 Median :  0.0000   Median :41.81   Median :  0.3664   Median : 247.0  
 Mean   :  0.8088   Mean   :41.03   Mean   : -1.7488   Mean   : 406.3  
 3rd Qu.:  0.0000   3rd Qu.:42.44   3rd Qu.:  1.8267   3rd Qu.: 582.0  
 Max.   :780.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin             precip       
 Min.   :  1.00   Min.   :-44.0   Min.   :-185.00   Min.   :  0.000  
 1st Qu.: 39.00   1st Qu.:133.0   1st Qu.:  28.00   1st Qu.:  0.000  
 Median : 77.00   Median :170.0   Median :  66.00   Median :  0.000  
 Mean   : 78.38   Mean   :170.8   Mean   :  63.87   Mean   :  8.666  
 3rd Qu.:116.00   3rd Qu.:211.0   3rd Qu.: 101.00   3rd Qu.:  2.000  
 Max.   :230.00   Max.   :360.0   Max.   : 210.00   Max.   :187.000  
     nevada    prof_nieve           longitud        latitud      
 Min.   :0   Min.   :   0.0000   Min.   :35.28   Min.   :-8.624  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.56   1st Qu.:-4.127  
 Median :0   Median :   0.0000   Median :41.29   Median :-1.229  
 Mean   :0   Mean   :   0.1379   Mean   :40.72   Mean   :-1.576  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.08   3rd Qu.: 1.363  
 Max.   :0   Max.   :1209.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  52.0  
 Median : 261.0  
 Mean   : 372.1  
 3rd Qu.: 639.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   :  1.0   Min.   : -2.0   Min.   :-63.00   Min.   : 84.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:128.0   1st Qu.: 67.00   1st Qu.:141.0   1st Qu.:0  
 Median :164.0   Median :161.0   Median : 96.00   Median :171.0   Median :0  
 Mean   :187.3   Mean   :167.6   Mean   : 96.74   Mean   :179.5   Mean   :0  
 3rd Qu.:294.0   3rd Qu.:202.0   3rd Qu.:127.00   3rd Qu.:214.0   3rd Qu.:0  
 Max.   :366.0   Max.   :379.0   Max.   :253.00   Max.   :300.0   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.80   1st Qu.:-5.616   1st Qu.:  59.0  
 Median :  0.0000   Median :41.88   Median :-2.039   Median : 261.0  
 Mean   :  0.1452   Mean   :41.43   Mean   :-2.224   Mean   : 358.4  
 3rd Qu.:  0.0000   3rd Qu.:42.78   3rd Qu.: 1.296   3rd Qu.: 594.0  
 Max.   :150.0000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :  3.0   Min.   :-63   Min.   :-133.00   Min.   : 620.0   Min.   :0  
 1st Qu.:106.0   1st Qu.:103   1st Qu.:  53.00   1st Qu.: 689.5   1st Qu.:0  
 Median :271.0   Median :147   Median : 101.00   Median : 782.0   Median :0  
 Mean   :217.3   Mean   :144   Mean   :  90.77   Mean   : 866.2   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194   3rd Qu.: 136.50   3rd Qu.: 939.0   3rd Qu.:0  
 Max.   :362.0   Max.   :332   Max.   : 240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -1.8237   1st Qu.:  44.0  
 Median :  0.000   Median :41.57   Median :  0.9517   Median : 251.0  
 Mean   :  2.675   Mean   :40.75   Mean   : -0.7228   Mean   : 604.5  
 3rd Qu.:  0.000   3rd Qu.:42.27   3rd Qu.:  2.1053   3rd Qu.: 916.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :-18.0   Min.   :-75.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 90.0   1st Qu.:208.0   1st Qu.:146.0   1st Qu.:  0.000   1st Qu.:0  
 Median :179.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :180.9   Mean   :229.3   Mean   :164.7   Mean   :  4.341   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :429.0   Max.   :322.0   Max.   :322.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud    
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25  
 Median :0    Median :28.44   Median :-16.33   Median :  33  
 Mean   :0    Mean   :28.38   Mean   :-16.06   Mean   : 382  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   : 61.0   Min.   :119.0   Min.   :-16.0   Min.   :  0.000   Min.   :0  
 1st Qu.:190.0   1st Qu.:245.0   1st Qu.:130.0   1st Qu.:  0.000   1st Qu.:0  
 Median :225.0   Median :282.0   Median :160.0   Median :  0.000   Median :0  
 Mean   :225.8   Mean   :280.5   Mean   :158.7   Mean   :  4.245   Mean   :0  
 3rd Qu.:261.0   3rd Qu.:315.0   3rd Qu.:190.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :365.0   Max.   :469.0   Max.   :332.0   Max.   :180.000   Max.   :0  
   prof_nieve           longitud        latitud          altitud      
 Min.   :   0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:   0.0000   1st Qu.:39.56   1st Qu.:-4.049   1st Qu.:  44.0  
 Median :   0.0000   Median :41.22   Median :-1.169   Median : 247.0  
 Mean   :   0.0048   Mean   :40.76   Mean   :-1.573   Mean   : 371.6  
 3rd Qu.:   0.0000   3rd Qu.:42.11   3rd Qu.: 1.363   3rd Qu.: 639.0  
 Max.   :1039.0000   Max.   :43.57   Max.   : 4.216   Max.   :2230.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt          tmax            tmin             precip       
 Min.   :189.0   Min.   :-80.0   Min.   :-240.00   Min.   :  0.000  
 1st Qu.:312.0   1st Qu.:116.0   1st Qu.:  18.00   1st Qu.:  0.000  
 Median :332.0   Median :150.0   Median :  53.00   Median :  0.000  
 Mean   :328.8   Mean   :146.7   Mean   :  51.02   Mean   :  9.014  
 3rd Qu.:349.0   3rd Qu.:179.0   3rd Qu.:  85.00   3rd Qu.:  2.000  
 Max.   :366.0   Max.   :320.0   Max.   : 204.00   Max.   :158.000  
     nevada    prof_nieve           longitud        latitud      
 Min.   :0   Min.   :   0.0000   Min.   :35.28   Min.   :-8.624  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:39.88   1st Qu.:-4.846  
 Median :0   Median :   0.0000   Median :41.38   Median :-1.885  
 Mean   :0   Mean   :   0.3441   Mean   :40.76   Mean   :-1.967  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.18   3rd Qu.: 1.168  
 Max.   :0   Max.   :1240.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  72.0  
 Median : 370.0  
 Mean   : 420.6  
 3rd Qu.: 687.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax              tmin              precip      
 Min.   :  1.0   Min.   :-196.00   Min.   :-252.000   Min.   :  0.00  
 1st Qu.: 86.0   1st Qu.:  27.00   1st Qu.: -36.000   1st Qu.:  0.00  
 Median :180.0   Median :  80.00   Median :  11.000   Median :  0.00  
 Mean   :180.8   Mean   :  78.39   Mean   :   8.653   Mean   : 12.38  
 3rd Qu.:275.0   3rd Qu.: 134.00   3rd Qu.:  59.000   3rd Qu.: 10.00  
 Max.   :366.0   Max.   : 255.00   Max.   : 176.000   Max.   :155.00  
     nevada    prof_nieve          longitud        latitud        
 Min.   :0   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0   1st Qu.:   0.000   1st Qu.:42.29   1st Qu.:  0.7789  
 Median :0   Median :   0.000   Median :42.47   Median :  1.2717  
 Mean   :0   Mean   :   7.961   Mean   :42.29   Mean   :  0.8635  
 3rd Qu.:0   3rd Qu.:   0.000   3rd Qu.:42.64   3rd Qu.:  1.7150  
 Max.   :0   Max.   :1199.000   Max.   :42.77   Max.   :  2.4378  
    altitud    
 Min.   : 890  
 1st Qu.:1971  
 Median :2247  
 Mean   :2195  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax          tmin             precip        nevada 
 Min.   :  1.0   Min.   :-64   Min.   :-117.00   Min.   :279   Min.   :0  
 1st Qu.:101.0   1st Qu.:120   1st Qu.:  66.00   1st Qu.:326   1st Qu.:0  
 Median :236.0   Median :157   Median : 102.00   Median :378   Median :0  
 Mean   :205.6   Mean   :163   Mean   :  98.67   Mean   :400   Mean   :0  
 3rd Qu.:304.0   3rd Qu.:204   3rd Qu.: 134.00   3rd Qu.:457   3rd Qu.:0  
 Max.   :366.0   Max.   :369   Max.   : 254.00   Max.   :639   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   :  0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.78   1st Qu.: -5.3456   1st Qu.:  44.0  
 Median :  0.0000   Median :41.81   Median :  0.3664   Median : 247.0  
 Mean   :  0.8088   Mean   :41.03   Mean   : -1.7488   Mean   : 406.3  
 3rd Qu.:  0.0000   3rd Qu.:42.44   3rd Qu.:  1.8267   3rd Qu.: 582.0  
 Max.   :780.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin            precip       
 Min.   :  1.00   Min.   : 37.0   Min.   :-55.00   Min.   :  0.000  
 1st Qu.: 55.00   1st Qu.:160.0   1st Qu.: 56.00   1st Qu.:  0.000  
 Median : 94.00   Median :189.0   Median : 83.00   Median :  0.000  
 Mean   : 89.83   Mean   :192.4   Mean   : 84.52   Mean   :  8.209  
 3rd Qu.:126.00   3rd Qu.:224.0   3rd Qu.:113.00   3rd Qu.:  2.000  
 Max.   :230.00   Max.   :360.0   Max.   :210.00   Max.   :160.000  
     nevada    prof_nieve           longitud        latitud      
 Min.   :0   Min.   :   0.0000   Min.   :35.28   Min.   :-8.624  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:38.88   1st Qu.:-4.767  
 Median :0   Median :   0.0000   Median :41.15   Median :-1.033  
 Mean   :0   Mean   :   0.0354   Mean   :40.49   Mean   :-1.606  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.00   3rd Qu.: 1.384  
 Max.   :0   Max.   :1209.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.:  32.0  
 Median : 108.0  
 Mean   : 263.8  
 3rd Qu.: 445.0  
 Max.   :1894.0  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin            precip          nevada 
 Min.   :  1.0   Min.   : -2.0   Min.   :-63.00   Min.   : 84.0   Min.   :0  
 1st Qu.: 97.0   1st Qu.:128.0   1st Qu.: 67.00   1st Qu.:141.0   1st Qu.:0  
 Median :164.0   Median :161.0   Median : 96.00   Median :171.0   Median :0  
 Mean   :187.3   Mean   :167.6   Mean   : 96.74   Mean   :179.5   Mean   :0  
 3rd Qu.:294.0   3rd Qu.:202.0   3rd Qu.:127.00   3rd Qu.:214.0   3rd Qu.:0  
 Max.   :366.0   Max.   :379.0   Max.   :253.00   Max.   :300.0   Max.   :0  
   prof_nieve          longitud        latitud          altitud      
 Min.   :  0.0000   Min.   :35.28   Min.   :-8.624   Min.   :   1.0  
 1st Qu.:  0.0000   1st Qu.:40.80   1st Qu.:-5.616   1st Qu.:  59.0  
 Median :  0.0000   Median :41.88   Median :-2.039   Median : 261.0  
 Mean   :  0.1452   Mean   :41.43   Mean   :-2.224   Mean   : 358.4  
 3rd Qu.:  0.0000   3rd Qu.:42.78   3rd Qu.: 1.296   3rd Qu.: 594.0  
 Max.   :150.0000   Max.   :43.57   Max.   : 4.216   Max.   :1894.0  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt          tmax          tmin             precip           nevada 
 Min.   :  3.0   Min.   :-63   Min.   :-133.00   Min.   : 620.0   Min.   :0  
 1st Qu.:106.0   1st Qu.:103   1st Qu.:  53.00   1st Qu.: 689.5   1st Qu.:0  
 Median :271.0   Median :147   Median : 101.00   Median : 782.0   Median :0  
 Mean   :217.3   Mean   :144   Mean   :  90.77   Mean   : 866.2   Mean   :0  
 3rd Qu.:306.0   3rd Qu.:194   3rd Qu.: 136.50   3rd Qu.: 939.0   3rd Qu.:0  
 Max.   :362.0   Max.   :332   Max.   : 240.00   Max.   :3361.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   :  0.000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:  0.000   1st Qu.:40.78   1st Qu.: -1.8237   1st Qu.:  44.0  
 Median :  0.000   Median :41.57   Median :  0.9517   Median : 251.0  
 Mean   :  2.675   Mean   :40.75   Mean   : -0.7228   Mean   : 604.5  
 3rd Qu.:  0.000   3rd Qu.:42.27   3rd Qu.:  2.1053   3rd Qu.: 916.0  
 Max.   :820.000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt          tmax            tmin           precip            nevada 
 Min.   :  1.0   Min.   :-18.0   Min.   :-75.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 90.0   1st Qu.:208.0   1st Qu.:146.0   1st Qu.:  0.000   1st Qu.:0  
 Median :179.0   Median :234.0   Median :172.0   Median :  0.000   Median :0  
 Mean   :180.9   Mean   :229.3   Mean   :164.7   Mean   :  4.341   Mean   :0  
 3rd Qu.:272.0   3rd Qu.:262.0   3rd Qu.:201.0   3rd Qu.:  0.000   3rd Qu.:0  
 Max.   :366.0   Max.   :429.0   Max.   :322.0   Max.   :322.000   Max.   :0  
   prof_nieve    longitud        latitud          altitud    
 Min.   :0    Min.   :27.82   Min.   :-17.89   Min.   :  14  
 1st Qu.:0    1st Qu.:28.05   1st Qu.:-16.56   1st Qu.:  25  
 Median :0    Median :28.44   Median :-16.33   Median :  33  
 Mean   :0    Mean   :28.38   Mean   :-16.06   Mean   : 382  
 3rd Qu.:0    3rd Qu.:28.48   3rd Qu.:-15.39   3rd Qu.:  64  
 Max.   :0    Max.   :28.95   Max.   :-13.60   Max.   :2371  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt          tmax             tmin            precip          nevada 
 Min.   :  1.0   Min.   :-142.0   Min.   :-200.0   Min.   : 87.0   Min.   :0  
 1st Qu.: 92.0   1st Qu.:   0.0   1st Qu.: -47.0   1st Qu.:148.0   1st Qu.:0  
 Median :157.0   Median :  39.0   Median :  -9.0   Median :191.0   Median :0  
 Mean   :180.9   Mean   :  44.3   Mean   : -11.4   Mean   :210.4   Mean   :0  
 3rd Qu.:293.0   3rd Qu.:  83.0   3rd Qu.:  26.0   3rd Qu.:258.0   3rd Qu.:0  
 Max.   :366.0   Max.   : 248.0   Max.   : 126.0   Max.   :529.0   Max.   :0  
   prof_nieve         longitud        latitud            altitud    
 Min.   :   0.00   Min.   :28.31   Min.   :-16.4992   Min.   : 507  
 1st Qu.:   0.00   1st Qu.:42.18   1st Qu.:  0.7789   1st Qu.:1894  
 Median :   0.00   Median :42.47   Median :  1.0544   Median :2230  
 Mean   :  14.45   Mean   :42.07   Mean   :  0.4129   Mean   :2092  
 3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.7150   3rd Qu.:2400  
 Max.   :1090.00   Max.   :42.77   Max.   :  2.4378   Max.   :2535  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax            tmin              precip      
 Min.   :  1.00   Min.   :-44.0   Min.   :-185.000   Min.   :  0.00  
 1st Qu.: 20.00   1st Qu.: 83.0   1st Qu.: -18.000   1st Qu.:  0.00  
 Median : 40.00   Median :109.0   Median :   4.000   Median :  0.00  
 Mean   : 44.64   Mean   :107.2   Mean   :   3.062   Mean   : 10.01  
 3rd Qu.: 64.00   3rd Qu.:133.0   3rd Qu.:  27.000   3rd Qu.:  4.00  
 Max.   :194.00   Max.   :238.0   Max.   : 104.000   Max.   :187.00  
     nevada    prof_nieve           longitud        latitud      
 Min.   :0   Min.   :   0.0000   Min.   :37.16   Min.   :-8.624  
 1st Qu.:0   1st Qu.:   0.0000   1st Qu.:40.78   1st Qu.:-3.789  
 Median :0   Median :   0.0000   Median :41.63   Median :-1.787  
 Mean   :0   Mean   :   0.4397   Mean   :41.39   Mean   :-1.486  
 3rd Qu.:0   3rd Qu.:   0.0000   3rd Qu.:42.19   3rd Qu.: 1.296  
 Max.   :0   Max.   :1021.0000   Max.   :43.57   Max.   : 4.216  
    altitud      
 Min.   :   1.0  
 1st Qu.: 513.0  
 Median : 687.0  
 Mean   : 691.1  
 3rd Qu.: 900.0  
 Max.   :1894.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBkaWEiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiA5CiogRGVzY3JpcGNpw7NuOiAKKiBGcmVjdWVuY2lhOiBkaWEKKiBWYXJpYWJsZXM6IGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZAoqIERpbWVuc2lvbmVzIGRlbCBtYXBhOiA1LDUKKiBJdGVyYWNpb25lczogMTAwMAoqIFBhcsOhbWV0cm9zIGFkaWNpb25hbGVzOiAKCmBgYHtyfQpzb3VyY2UoIi4uLy4uL2xpYi9zb20tdXRpbHMuUiIpCnNvdXJjZSgiLi4vLi4vbGliL21hcHMtdXRpbHMuUiIpCmBgYAoKIyBDYXJnYSBkZWwgbW9kZWxvIGRlc2RlIGRpc2NvCgpgYGB7cn0KbXByLnNldF9iYXNlX3BhdGhfYW5hbHlzaXMoKQptb2RlbCA8LSBtcHIubG9hZF9tb2RlbCgic29tLTAwOS5yZHMueHoiKQpzdW1tYXJ5KG1vZGVsKQpgYGAKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjaGFuZ2VzIikKYGBgCgojIENhcmdhIGRlbCBkYXRhc2V0IGRlIGVudHJhZGEKCmBgYHtyfQpkZiA8LSBtcHIubG9hZF9kYXRhKCJkYXRvc19kaWFfMmsuY3N2Lnh6IikKYGBgCgpgYGB7cn0KZGYKYGBgCgpgYGB7cn0Kc3VtbWFyeShkZikKYGBgCgojIENhcmdhIGRlIGxvcyBtYXBhcwoKYGBge3J9CndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpCnNwYWluIDwtIHN1YnNldCh3b3JsZCwgYWRtaW4gPT0gIlNwYWluIikKYGBgCgojIE1hcGEgZGUgZGVuc2lkYWQKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjb3VudCIsIHNoYXBlID0gInN0cmFpZ2h0IiwgcGFsZXR0ZS5uYW1lID0gbXByLmRlZ3JhZGUuYmxldSkKYGBgCgpOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNlbGRhOgoKYGBge3J9Cm5iIDwtIHRhYmxlKG1vZGVsJHVuaXQuY2xhc3NpZikKcHJpbnQobmIpCmBgYApDb21wcm9iYWNpw7NuIGRlIG5vZG9zIHZhY8Otb3M6CgpgYGB7cn0KZGltX21vZGVsIDwtIDUqNTsKbGVuX25iID0gbGVuZ3RoKG5iKTsKZW1wdHlfbm9kZXMgPC0gZGltX21vZGVsICE9IGxlbl9uYjsKaWYgKGVtcHR5X25vZGVzKSB7CiAgcHJpbnQocGFzdGUoIltXYXJuaW5nXSBFeGlzdGVuIG5vZG9zIHZhY8Otb3M6ICIsIGxlbl9uYiwgIi8iLCBkaW1fbW9kZWwpKQp9CmBgYAoKIyBNYXBhIGRlIGRpc3RhbmNpYSBlbnRyZSB2ZWNpbm9zCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iZGlzdC5uZWlnaGJvdXJzIiwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMgSW5mbHVlbmNpYSBkZSBsYXMgdmFyaWFibGVzCgpgYGB7cn0KbW9kZWxfY29sbmFtZXMgPSBjKCJmZWNoYV9jbnQiLCAidG1heCIsICJ0bWluIiwgInByZWNpcCIsICJsb25naXR1ZCIsICJsYXRpdHVkIiwgImFsdGl0dWQiKQptb2RlbF9uY29sID0gbGVuZ3RoKG1vZGVsX2NvbG5hbWVzKQpgYGAKCiMjIE1hcGEgZGUgdmFyaWFibGVzLgoKYGBge3J9CnBsb3QobW9kZWwsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIyBNYXBhIGRlIGNhbG9yIHBvciB2YXJpYWJsZQoKYGBge3J9CnBhcihtZnJvdz1jKDMsNCkpCmZvciAoaiBpbiAxOm1vZGVsX25jb2wpIHsKICBwbG90KG1vZGVsLCB0eXBlPSJwcm9wZXJ0eSIsIHByb3BlcnR5PWdldENvZGVzKG1vZGVsLDEpWyxqXSwKICAgIHBhbGV0dGUubmFtZT1tcHIuY29vbEJsdWVIb3RSZWQsCiAgICBtYWluPW1vZGVsX2NvbG5hbWVzW2pdLAogICAgY2V4PTAuNSwgc2hhcGUgPSAic3RyYWlnaHQiKQp9CmBgYAoKIyMgQ29ycmVsYWNpw7NuIHBhcmEgY2FkYSBjb2x1bW5hIGRlbCB2ZWN0b3IgZGUgbm9kb3MKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgY29yIDwtIGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLCAyLCBtcHIud2VpZ2h0ZWQuY29ycmVsYXRpb24sIHc9bmIsIHNvbT1tb2RlbCkKICBwcmludChjb3IpCn0KYGBgCgpSZXByZXNlbnRhY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBlbiB1biBtYXBhIGRlIGZhY3RvcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIHBsb3QoY29yWzEsXSwgY29yWzIsXSwgeGxpbT1jKC0xLDEpLCB5bGltPWMoLTEsMSksIHR5cGU9Im4iKQogIGxpbmVzKGMoLTEsMSksYygwLDApKQogIGxpbmVzKGMoMCwwKSxjKC0xLDEpKQogIHRleHQoY29yWzEsXSwgY29yWzIsXSwgbGFiZWxzPW1vZGVsX2NvbG5hbWVzLCBjZXg9MC43NSkKICBzeW1ib2xzKDAsMCxjaXJjbGVzPTEsaW5jaGVzPUYsYWRkPVQpCn0KYGBgCgpJbXBvcnRhbmNpYSBkZSBjYWRhIHZhcmlhYmxlIC0gdmFyaWFuemEgcG9uZGVyYWRhIHBvciBlbCB0YW1hw7FvIGRlIGxhIGNlbGRhOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBzaWdtYTIgPC0gc3FydChhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwyLGZ1bmN0aW9uKHgsZWZmZWN0aWYpCiAgICAge208LXN1bShlZmZlY3RpZiooeC13ZWlnaHRlZC5tZWFuKHgsZWZmZWN0aWYpKV4yKS8oc3VtKGVmZmVjdGlmKS0xKX0sCiAgICAgZWZmZWN0aWY9bmIpKQogIHByaW50KHNvcnQoc2lnbWEyLGRlY3JlYXNpbmc9VCkpCn0KYGBgCgojIENsdXN0ZXJpbmcKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgaGFjIDwtIG1wci5oYWMobW9kZWwsIG5iKQp9CmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMyBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTMpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0zKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDQgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz00KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNSBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTUpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz01KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNiBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTYpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz02KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDggY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz04KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9OCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDEwIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MTApCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0xMCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKICBkZi5jbHVzdGVyMDkgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT05KQogIGRmLmNsdXN0ZXIxMCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEwKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA5IDwtIHNlbGVjdChkZi5jbHVzdGVyMDksIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIxMCA8LSBzZWxlY3QoZGYuY2x1c3RlcjEwLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdLCBkaW0oZGYuY2x1c3RlcjA5KVsxXSwgZGltKGRmLmNsdXN0ZXIxMClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiwgImNsdXN0ZXIwOSIsICJjbHVzdGVyMTAiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjEwKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKICBkZi5jbHVzdGVyMDkuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOSkKICBkZi5jbHVzdGVyMTAuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIxMCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIxMC5ncm91cGVkKQpgYGAK